package saxion.security.android;

import java.io.File;
import java.io.IOException;

import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.SealedObject;

import nl.saxion.security.encryption.TransformerAES;
import nl.saxion.security.synchronize.FileIncHash;
import nl.saxion.security.synchronize.ObjectSerializer;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

/**
 * @author Saxion-Security The activity which handles the browsing of the
 *         folders and opening of files
 */
public class FilesActivity extends Activity {

	private List<String> directoryEntries = new ArrayList<String>();
	private File currentDirectory = new File("");
	private ListView lView;
	private String rootfolderLocation = "";
	
	//load strings from strings.xml
	private String openFileTitle;
	private String openFileMessage;
	private String openFileBtnOpen;
	private String openFileBtnSend;
	private String openFileBtnCancel;
	
	private String doesntExsistTitle;
	private String doesntExsistMessage;
	private String doesntExsistBtn;
	
	private String listRefresh;
	private String listDirUp;
	
	
	private TransformerAES transformer;
	public String encryptedFolderLocation = "";
	public String decryptedFolderLocation = "";
	
	private boolean fileopen = false;
	private String openFile;
	private SharedPreferences sharedPreferences;
	private byte[] password = null;
	
	private String FILELIST= "filelist";
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		 //gets the right strings from strings.xml
        openFileTitle = getString(R.string.files_openfile_title);
        openFileMessage = getString(R.string.files_openfile_message);
        openFileBtnOpen = getString(R.string.files_openfile_btn_open);
        openFileBtnSend = getString(R.string.files_openfile_btn_send);
        openFileBtnCancel = getString(R.string.files_openfile_btn_cancel);
        doesntExsistTitle = getString(R.string.files_doesntexsist_title);
        doesntExsistMessage = getString(R.string.files_doesntexsist_message);
        doesntExsistBtn = getString(R.string.files_doesntexsist_btn);
        listRefresh = getString(R.string.files_list_refresh);
        listDirUp = getString(R.string.files_list_dir_up);
        
        //populates the view with the contents from the xml file filestab.xml
		setContentView(R.layout.filestab);
		lView = (ListView) findViewById(R.id.list);
		browseToRoot();
		
		//set an onclick listener
		lView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
				String selectedFromList = (String) (lView.getItemAtPosition(arg2));
				onListItemClick(selectedFromList);
			}
		});
		
		//create the transformer class
		transformer = new TransformerAES();

		//set the prefereces to strings
		sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		encryptedFolderLocation = sharedPreferences.getString("encryptedFolderLocation" , "");
		decryptedFolderLocation = sharedPreferences.getString("decryptedFolderLocation" , "");
        
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onResume()
	 */
	protected void onResume() {
		super.onResume();

		try {
			//save the edited file
			saveEditFile();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		browseToRoot();
	}
	
	private void saveEditFile() throws NoSuchAlgorithmException, IOException
	{
		if(fileopen)
		{
			Log.v("ONRESUME", "file = open");
			
			File file = new File(getFileStreamPath(openFile).getAbsolutePath());
			String cleanHash = transformer.generateHash(file.getAbsolutePath());
			
			
			SealedObject sealedKey = (SealedObject)ObjectSerializer.deserialize(sharedPreferences.getString("sealedKey", ""));
			byte[] originalKey = null;
			try {
				originalKey = (byte[]) transformer.decryptObject(password, sealedKey);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			
			ArrayList<FileIncHash> fileList = getFileList();
			for(FileIncHash fileIncHash : fileList)
			{
				if(fileIncHash.getName().equals(file.getName()))
				{		
					encryptFile(openFile, originalKey);
					fileIncHash.setEncryptedHash(transformer.generateHash(file.getAbsolutePath()));
					fileIncHash.setDecryptedHash(cleanHash);
					fileIncHash.setLastModified(fileIncHash.getLastModiDate());
					break;
				}
			}
			saveFileList(fileList); //save to config..

			fileopen =false;
		}
	}
	
	/**
	 * Gets the file list from the preferences
	 * @return ArrayList with all the files
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<FileIncHash> getFileList()
	{
		//gets the file list from the preferences
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		ArrayList<FileIncHash> fileList = null;
		try {
			fileList = (ArrayList<FileIncHash>)ObjectSerializer.deserialize(sharedPreferences.getString(FILELIST, ObjectSerializer.serialize(new ArrayList<FileIncHash>())));
		} catch (IOException e) {
		
			e.printStackTrace();
		}
		return fileList;
	}

	/**
	 * Sets the file list to the preferences
	 */
	private void saveFileList(ArrayList<FileIncHash> newFiles)
	{
		 //saves teh filelist to the preference
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		SharedPreferences.Editor editor = sharedPreferences.edit();
		try {
			editor.putString(FILELIST, ObjectSerializer.serialize(newFiles));
			  editor.commit(); 
		} catch (IOException e) {
		
			e.printStackTrace();
		}
	}


	/**
	 * It will browse to the root where the encrypted files are saved The method
	 * used browseTo()
	 */
	public void browseToRoot() {
		if(sharedPreferences == null)
			sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		
		rootfolderLocation = sharedPreferences.getString("encryptedFolderLocation", "");

		browseTo(new File(rootfolderLocation));

	}

	/**according to
	 * This function browses up one level  the field:
	 * currentDirectory
	 */
	private void upOneLevel() {

		if (this.currentDirectory.getParent() != null)
			this.browseTo(this.currentDirectory.getParentFile());
	}

	/**
	 * Will browse to a directory or if it is a file it will open an intent to
	 * select the application to open the file
	 * 
	 * @param aDirectory
	 *            The file/directory to browse/open or send.
	 */
	private void browseTo(final File aDirectory) {
		if (aDirectory.exists()) {
			if (aDirectory.isDirectory()) {
				this.currentDirectory = aDirectory;
				fill(aDirectory.listFiles());

			} else {
				AlertDialog alertDialog = new AlertDialog.Builder(this).create();
				alertDialog.setTitle(openFileTitle);
				alertDialog.setMessage(openFileMessage);
				alertDialog.setButton(openFileBtnOpen,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,int which) {								
									openFile(aDirectory);
							}
						});
				alertDialog.setButton2(openFileBtnSend,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
								//Delete
							}
						});
				alertDialog.setButton3(openFileBtnCancel,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
								// Do Nothing
							}
						});
				alertDialog.show();

			}
		} else {
			// is not a file
			AlertDialog alertDialog = new AlertDialog.Builder(this).create();
			alertDialog.setTitle(doesntExsistTitle);
			alertDialog.setMessage(doesntExsistMessage);
			
			alertDialog.setButton2(doesntExsistBtn,
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							// Do Nothing
						}
					});

			alertDialog.show();
		}
	}
	
	private void openFile(final File file)
	{
		 //create an AlertDIalog
        LayoutInflater factory = LayoutInflater.from(this);
        final View textEntryView = factory.inflate(R.layout.insertpw_dialog, null);
        AlertDialog alert = new AlertDialog.Builder(FilesActivity.this)
            .setTitle(R.string.password_dialog_title)
            .setView(textEntryView)
            .setPositiveButton("Openen", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                	//onclick event, if the user clicks on this button
                	Context context = getApplicationContext();
					int duration = Toast.LENGTH_SHORT;

                	byte[] originalKey = null;
					try {
						//decrypt the stored sealed key with the password
						EditText pwInput = (EditText) textEntryView.findViewById(R.id.passwordFileOpen);
						String inputpwd = pwInput.getText().toString();
						
						byte[] thePassword = transformer.generateKey(inputpwd);
						SealedObject sealedKey = (SealedObject)ObjectSerializer.deserialize(sharedPreferences.getString("sealedKey", ""));
						originalKey = (byte[]) transformer.decryptObject(thePassword, sealedKey);
						
						try{
							
							//the originalKey cannot be null
							if(!originalKey.equals(null)){
							
								fileopen = true;
								openFile = file.getName();
								Log.v("FILENAME",file.getName());

								File decryptedFile = decryptFile(file, originalKey);
								//open the file
						        Uri internal = Uri.fromFile(decryptedFile);
								Intent myIntent = new Intent(Intent.ACTION_VIEW);
								String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(decryptedFile).toString());
								String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
								myIntent.setDataAndType(internal, mimetype);
								startActivity(myIntent);
								password = thePassword; // save the password temporarily
							}
							
						} catch (Exception e) {
							//something wrong with the encryption
							Toast toast = Toast.makeText(context, R.string.password_encryption_wrong, duration);
							toast.show();
						}
						
					} catch (Exception e) {
						//false password
						Toast toast = Toast.makeText(context, R.string.password_toast_wrong, duration);
						toast.show();
					}
					

					
                }
            })
            .setNegativeButton("Annuleren", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                	//do nothing
                }
            })
            .create();
        //creates the alert and shows it
		alert.show();
	}

	/**
	 * Fills the lView with the files and directories
	 * 
	 * @param Files
	 *            An array of the files and directories to add
	 */
	private void fill(File[] files) {
		this.directoryEntries.clear();
		this.directoryEntries.add(listRefresh);

		if (this.currentDirectory.getParent() != null) {
			if (!this.currentDirectory.getPath().contentEquals(rootfolderLocation)) {
				this.directoryEntries.add(listDirUp);
			}
			// Files are saved relative so we need to add the whole path
			int currentPathStringLenght = this.currentDirectory.getAbsolutePath().length();
			for (File file : files) {
				this.directoryEntries.add(file.getAbsolutePath().substring(currentPathStringLenght));
			}
			
			ArrayAdapter<String> directoryList = new ArrayAdapter<String>(this,R.layout.filelist, this.directoryEntries);
			lView.setAdapter(directoryList);
		}
	}

	/**
	 * When a ListItem is clicked its gets the file from a string.
	 * 
	 * @param selected
	 *            The string of the selected file example : /selectedpdf.pdf
	 */
	private void onListItemClick(String selected) {
		String selectedFileString = selected;
		if (selectedFileString.equals(listRefresh)) {
			// Refresh
			this.browseTo(this.currentDirectory);
		} else if (selectedFileString.equals(listDirUp)) {
			this.upOneLevel();
		} else {
			File clickedFile = null;
			// Files are saved relative so we need to add the whole path
			clickedFile = new File(this.currentDirectory.getAbsolutePath()
					+ selected);

			if (clickedFile != null)
				this.browseTo(clickedFile);

		}
	}
	
	/**
	 * Decrypt a encryptedFile to internal storage
	 * @param encryptedFile
	 * @return decryptd file
	 */
	private File decryptFile(File encryptedFile, byte[] originalKey){
	    OutputStream out;
	    File decryptedFile = null;


		try {
			out = openFileOutput(encryptedFile.getName(), Context.MODE_WORLD_WRITEABLE | Context.MODE_WORLD_READABLE );
			transformer.decryptFile2(originalKey, encryptedFile.getAbsolutePath(), out);
			decryptedFile = getFileStreamPath(encryptedFile.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}

		return decryptedFile;
    }

	/**
	 * Encryptfile to encryption folder location
	 * @param file
	 */
	private void encryptFile(String file, byte[] originalKey){

		try {
		    	File internalFile = getFileStreamPath(file);
		    	transformer.encryptFile(originalKey, internalFile.getAbsolutePath(), encryptedFolderLocation +"/"+internalFile.getName() );
		    	internalFile.delete();
		} catch (Exception e) {
				e.printStackTrace();
		}

	}

}
